package com.ledi.guns.modular.ledipay.service.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ledi.guns.common.exception.AppCheckException;
import com.ledi.guns.common.persistence.dao.BillDetailMapper;
import com.ledi.guns.common.persistence.dao.BillWeixinMapper;
import com.ledi.guns.common.persistence.dao.SchoolInfoMapper;
import com.ledi.guns.common.persistence.model.BillDetail;
import com.ledi.guns.common.persistence.model.BillWeixin;
import com.ledi.guns.common.persistence.model.SchoolInfo;
import com.ledi.guns.core.util.DateUtil;
import com.ledi.guns.core.util.PayUtil;
import com.ledi.guns.core.util.StringUtil;
import com.ledi.guns.core.util.SystemConstans;
import com.ledi.guns.modular.ledipay.service.EduPayObserver;

@Service
public class EduPayWexinObserver implements EduPayObserver {

	protected final static Logger logger = LoggerFactory.getLogger(EduPayWexinObserver.class);

	@Autowired
	private BillDetailMapper billDetailMapper;
	@Autowired
	private BillWeixinMapper billWeixinMapper;
	@Autowired
	private SchoolInfoMapper schoolInfoMapper;
	@Autowired
	BillStreamServiceImpl streamService;
	@Value("${weixin.appid}")
	private String appid;
	@Value("${weixin.secret}")
	private String secret;
	@Value("${weixin.openIdUrl}")
	private String openIdUrl;
	@Value("${weixin.notifyUrl}")
	private String notifyUrl;
	@Value("${weixin.mchId}")
	private String mchId;
	@Value("${weixin.shhkey}")
	private String shhkey;
	@Value("${weixin.weixinPayUrl}")
	private String weixinPayUrl;
	@Value("${weixin.weixinQueryUrl}")
	private String weixinQueryUrl;
	@Value("${weixin.closeWeixinUrl}")
	private String closeWeixinUrl;

	public Map<String, String> createWeixinPay(String oldBillDetailId, String code, String billDetailId,
			String sub_mch_id,
			BigDecimal totalDetail,
			HttpServletRequest request, HttpServletResponse response, BillDetail billDetail) {

		Map<String, String> mapResult = new HashMap<String, String>();
		try {
			/*------1.根据code获取微信用户的openId和access_token------- */
			String openid = null;
			if (StringUtil.isBlank(oldBillDetailId)) {
				try {
					List<Object> list = accessToken(code);
					openid = list.get(1).toString();
				} catch (Exception e) {
					logger.error("根据code获取微信用户的openId出现错误", e);
					throw new AppCheckException("school.zhangdan.scan.openid.file.code",
							"school.zhangdan.scan.openid.file.message");
				}
			} else {
				BillWeixin billWeixin = new BillWeixin();
				billWeixin.setBillDetailId(oldBillDetailId);
				billWeixin = billWeixinMapper.selectOne(billWeixin);
				openid = billWeixin.getOpenid();
			}

			/*------2.生成预支付订单需要的的package数据------- */
			// 随机数
			String nonce_str = PayUtil.getNonceStr();
			// 订单生成的机器 IP
			String spbill_create_ip = request.getHeader("X-Real-IP");
			logger.error("【测试，查看用户IP】" + spbill_create_ip);
			// 交易类型 ：jsapi代表微信公众号支付
			String trade_type = "JSAPI";
			// 这里notify_url是 微信处理完支付后的回调的应用系统接口url。
			String notify_url = notifyUrl;

			logger.error("【测试，查看学校的商户号:】" + sub_mch_id);
			if (sub_mch_id == null || "".equals(sub_mch_id)) {
				logger.error("学校商户号为空");
				throw new AppCheckException("school.zhangdan.scan.sub.file.code",
						"school.zhangdan.scan.sub.file.message");
			}

			SortedMap<String, String> packageParams = new TreeMap<String, String>();
			packageParams.put("appid", appid);
			packageParams.put("mch_id", mchId);
			packageParams.put("sub_mch_id", sub_mch_id);
			packageParams.put("nonce_str", nonce_str);
			packageParams.put("body", "费用");
			packageParams.put("out_trade_no", billDetailId);
			totalDetail = totalDetail.multiply(new BigDecimal(100));
			packageParams.put("total_fee", totalDetail.intValue() + "");
			packageParams.put("spbill_create_ip", spbill_create_ip);
			packageParams.put("notify_url", notify_url);
			packageParams.put("trade_type", trade_type);
			packageParams.put("openid", openid);

			/*------3.根据package数据生成预支付订单号的签名sign------- */
			packageParams.put("key", shhkey);
			String paySign = PayUtil.createSign(packageParams);
			packageParams.remove("key");
			packageParams.put("sign", paySign);

			/*------4.生成需要提交给统一支付接口的xml数据-------*/
			String xml = "";
			try {
				xml = PayUtil.mapToXml(packageParams);
				logger.error("【测试，查看提交给统一支付接口的xml数据】" + xml);
			} catch (Exception e) {
				logger.error("生成需要提交给统一支付接口的xml数据转换失败", e);
				throw new AppCheckException("school.zhangdan.scan.mapToXml.file.code",
						"school.zhangdan.scan.mapToXml.file.message");
			}

			/*------5.调用统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder 生产预支付订单----------*/

			Map map = PayUtil.getPayNo(weixinPayUrl, xml);
			logger.error("【测试，调用统一支付接口返回的数据】" + map.toString());
			// 签名失败 参数格式校验错误
			if ("FAIL".equals(map.get("return_code"))) {
				logger.error("[请求微信预支付接口失败：]" + (String) map.get("return_msg"));
				throw new AppCheckException("school.zhangdan.scan.send.file.code",
						"school.zhangdan.scan.send.file.message", (String) map.get("return_msg"));
			}
			// 请求后值是否错误
			if ("FAIL".equals(map.get("result_code"))) {
				logger.error("[请求微信预支付接口失败：]" + map.get("err_code_des"));
				throw new AppCheckException("school.zhangdan.scan.send.file.code",
						"school.zhangdan.scan.send.file.message", (String) map.get("err_code_des"));
			}

			/*------6.成功后进行入库操作----------*/
			mapResult.put("prepay_id", (String) map.get("prepay_id"));
			billDetail.setBillStatus(SystemConstans.BILL_STATUS_SEND_SUCCESS);
			billDetailMapper.updateById(billDetail);
			BillWeixin billWeixin = new BillWeixin();
			billWeixin.setBillDetailId(billDetailId);
			billWeixin.setOpenid(openid);
			billWeixin.setBillEndTime(DateUtil.addDaysToDate(new Date(), 1));
			billWeixin.setBillStatus(SystemConstans.BILL_STATUS_SEND_SUCCESS);
			billWeixin.setSubMchId(sub_mch_id);
			billWeixinMapper.insert(billWeixin);
			streamService.billStream("发送账单", billDetailId, SystemConstans.API_INVOKE_TYPE_SEND,
					SystemConstans.PAY_WAY_WEIXIN, packageParams.toString(), map.toString());
		} catch (Exception e) {
			if (e instanceof AppCheckException) {
				throw (AppCheckException) e;
			}
			throw new AppCheckException("school.zhangdan.scan.send.file.code",
					"school.zhangdan.scan.send.file.message", "统一支付接口获取预支付订单出错");
		}
		return mapResult;
	}

	/**
	 * 通过微信用户的code换取网页授权access_token
	 *
	 * @throws IOException
	 * @throws ClientProtocolException
	 */
	private List<Object> accessToken(String code) throws ClientProtocolException, IOException {

		List<Object> list = new ArrayList<Object>();
		String url = openIdUrl + "?appid="
				+ appid + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code";
		HttpClient client = new DefaultHttpClient();
		HttpPost post = new HttpPost(url);
		HttpResponse res = client.execute(post);
		if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
			HttpEntity entity = res.getEntity();
			String str = org.apache.http.util.EntityUtils.toString(entity, "utf-8");
			ObjectMapper mapper = new ObjectMapper();
			Map<String, Object> jsonOb = mapper.readValue(str, Map.class);
			list.add(jsonOb.get("access_token"));
			list.add(jsonOb.get("openid"));
		}
		return list;
	}

	/**
	 * 方法描述: [查询订单是否完成支付]<br/>
	 * 初始作者: 许芬<br/>
	 * 创建日期: 2018年1月17日-上午10:33:32<br/>
	 * 开始版本: 2.0.0<br/>
	 * =================================================<br/>
	 * 修改记录：<br/>
	 * 修改作者 日期 修改内容<br/>
	 * ================================================<br/>
	 *
	 * @param billDetailId
	 * @param string
	 * @return
	 *         boolean
	 */
	public Map<String, String> havePay(BillWeixin billWeixin, String billDetailId, String subMchId) {

		Map resultMap = new HashMap();
		/*------1.组装参数-------*/
		// 随机数
		String nonce_str = PayUtil.getNonceStr();
		SortedMap<String, String> packageParams = new TreeMap<String, String>();
		packageParams.put("appid", appid);
		packageParams.put("mch_id", mchId);
		packageParams.put("sub_mch_id", subMchId);
		packageParams.put("out_trade_no", billDetailId);
		packageParams.put("nonce_str", nonce_str);

		/*------2.生成签名-------*/
		packageParams.put("key", shhkey);
		String paySign = PayUtil.createSign(packageParams);
		packageParams.put("sign", paySign);
		packageParams.remove("key");

		/*------3.生成需要提交给统一支付接口的xml数据-------*/
		String xml = "";
		try {
			xml = PayUtil.mapToXml(packageParams);
			logger.error("【查看提交给微信查询接口的xml数据】" + xml);
		} catch (Exception e) {
			logger.error("生成需要提交给微信查询接口的xml数据转换失败", e);
			throw new AppCheckException("school.zhangdan.scan.mapToXml.file.code",
					"school.zhangdan.scan.mapToXml.file.message");
		}

		/*------5.调用查询接口https://api.mch.weixin.qq.com/pay/orderquery 查询支付订单----------*/
		Map map = PayUtil.getPayNo(weixinQueryUrl, xml);
		logger.error("【调用微信查询接口返回的数据】" + map.toString());
		// 签名失败 参数格式校验错误
		if ("FAIL".equals(map.get("return_code"))) {
			logger.error("[请求微信查询接口失败：]" + (String) map.get("return_msg"));
			throw new AppCheckException("school.zhangdan.scan.send.file.code",
					"school.zhangdan.scan.send.file.message", (String) map.get("return_msg"));

		}
		// 请求后值是否错误
		if ("FAIL".equals(map.get("result_code"))) {
			logger.error("[请求微信查询接口失败：]" + map.get("err_code_des"));
			throw new AppCheckException("school.zhangdan.scan.send.file.code",
					"school.zhangdan.scan.send.file.message", (String) map.get("err_code_des"));
		}
		int billStatus = 2;
		if ("SUCCESS".equals(map.get("trade_state"))) {

			billStatus = SystemConstans.BILL_STATUS_FINISH;
			billWeixin.setWeixinTransactionId((String) map.get("transaction_id"));
			billWeixin.setPayTime(DateUtil.parseDate1((String) map.get("time_end")));
			billWeixin.setBillStatus(billStatus);
			billWeixin.setComment("扭转未支付，账单关闭，" + DateUtil.getTime());
			billWeixinMapper.updateById(billWeixin);
			updateBillStatus(billWeixin.getBillDetailId(), billStatus,
					SystemConstans.PAY_WAY_WEIXIN);
			logger.info("扭转未支付账单，为成功账单，billDetailId=" + billWeixin.getBillDetailId());
		} else {
			if (billWeixin.getBillEndTime().getTime() <= System.currentTimeMillis()) {
				billStatus = SystemConstans.BILL_STATUS_CANCEL;
				billWeixin.setBillStatus(billStatus);
				billWeixin.setComment("过期未支付，账单关闭，" + DateUtil.getTime());
				billWeixinMapper.updateById(billWeixin);
				updateBillStatus(billWeixin.getBillDetailId(), billStatus,
						SystemConstans.PAY_WAY_WEIXIN);
				logger.info("关闭过期未支付账单，billDetailId=" + billWeixin.getBillDetailId());
			}
		}

		resultMap.put("trade_state", map.get("trade_state"));
		resultMap.put("transaction_id", map.get("transaction_id"));
		resultMap.put("time_end", map.get("time_end"));
		return resultMap;
	}

	/**
	 * 关闭微信账单
	 * 初始作者: 许芬<br/>
	 * 创建日期: 2018年1月19日-下午1:44:09<br/>
	 * 开始版本: 2.0.0<br/>
	 * =================================================<br/>
	 * 修改记录：<br/>
	 * 修改作者 日期 修改内容<br/>
	 * ================================================<br/>
	 *
	 * @param billDetailId
	 * @param schoolId
	 *            void
	 */
	public void closeWinxinBill(String billDetailId, Long schoolId) {

		/*------1.组装参数-------*/
		// 随机数
		SchoolInfo schoolInfo = schoolInfoMapper.selectById(schoolId);
		String nonce_str = PayUtil.getNonceStr();
		SortedMap<String, String> packageParams = new TreeMap<String, String>();
		packageParams.put("appid", appid);
		packageParams.put("mch_id", mchId);
		packageParams.put("sub_mch_id", schoolInfo.getSubMchId());
		packageParams.put("out_trade_no", billDetailId);
		packageParams.put("nonce_str", nonce_str);

		/*------2.生成签名-------*/
		packageParams.put("key", shhkey);
		String paySign = PayUtil.createSign(packageParams);
		packageParams.put("sign", paySign);
		packageParams.remove("key");

		/*------3.生成需要提交给统一支付接口的xml数据-------*/
		String xml = "";
		try {
			xml = PayUtil.mapToXml(packageParams);
			logger.error("【查看提交给微信关闭账单接口的xml数据】" + xml);
		} catch (Exception e) {
			logger.error("生成需要提交给微信关闭账单接口的xml数据转换失败", e);
			throw new AppCheckException("school.zhangdan.scan.mapToXml.file.code",
					"school.zhangdan.scan.mapToXml.file.message");
		}

		/*------5.调用关闭账单接口----------*/
		Map map = PayUtil.getPayNo(closeWeixinUrl, xml);
		logger.error("【调用微信关闭账单接口返回的数据】" + map.toString());
		// 签名失败 参数格式校验错误
		if ("FAIL".equals(map.get("return_code"))) {
			logger.error("[请求微信关闭账单接口失败：]" + (String) map.get("return_msg"));
			throw new AppCheckException("school.zhangdan.scan.send.file.code",
					"school.zhangdan.scan.send.file.message", (String) map.get("return_msg"));

		}
		// 请求后值是否错误
		if ("FAIL".equals(map.get("result_code"))) {
			logger.error("[请求微信关闭账单接口失败：]" + map.get("err_code_des"));
			throw new AppCheckException("school.zhangdan.scan.send.file.code",
					"school.zhangdan.scan.send.file.message", (String) map.get("err_code_des"));
		}
	}

	public void updateBillStatus(String billDetailId, int payStatus, String payWay) {

		BillDetail billDetail = new BillDetail();
		billDetail.setBillDetailId(billDetailId);
		billDetail = billDetailMapper.selectOne(billDetail);
		billDetail.setPayTime(new Date());
		billDetail.setPayWay(payWay);
		billDetail.setBillStatus(payStatus);
		billDetailMapper.updateById(billDetail);
	}

	@Override
	public boolean sendBill(Long billId) {

		return false;
	}

	@Override
	public String addSchool(SchoolInfo School) {

		// TODO Auto-generated method stub
		return null;
	}

}
